﻿/*
** Xin YUAN, 2022, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////
#ifndef __CTL_IMAGE_COLOR_SPACE_H__
#define __CTL_IMAGE_COLOR_SPACE_H__
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
namespace CTL {
////////////////////////////////////////////////////////////////////////////////

//Rgb2Hsv

inline void Rgb2Hsv(double dR, double dG, double dB, double& dH, double& dS, double& dV) noexcept
{
	// r,g,b values are from 0 to 1
	// h = [0,360], s = [0,1], v = [0,1]
	// if s == 0, then h = -1 (undefined)

	double dmin, dmax;
	if ( dR > dG ) {
		dmin = dG;
		dmax = dR;
	}
	else {
		dmin = dR;
		dmax = dG;
	}
	if ( dmin > dB )
		dmin = dB;
	if ( dmax < dB )
		dmax = dB;
	double delta = dmax - dmin;

	dV = dmax; // v

	if ( DefaultCompareTrait<double>::IsEQ(dmax, 0.0) ) {
		// r = g = b = 0 -> s = 0, v is undefined
		dS = 0.0;
		dH = -1.0;
		return ;
	}
	dS = delta / dmax; // s

	if ( DefaultCompareTrait<double>::IsEQ(delta, 0.0) ) {
		dH = 0.0;
		return ;
	}

	if ( dR == dmax ) {
		if ( dG >= dB )
			dH = (dG - dB) / delta; // between yellow & magenta
		else
			dH = (dG - dB) / delta + 6.0;
	}
	else if ( dG == dmax ) {
		dH = 2.0 + (dB - dR) / delta; // between cyan & yellow
	}
	else if ( dB == dmax ) {
		dH = 4.0 + (dR - dG) / delta; // between magenta & cyan
	}
	dH *= 60.0; // degrees
}

//Hsv2Rgb

inline void Hsv2Rgb(double dH, double dS, double dV, double& dR, double& dG, double& dB) noexcept
{
	// r,g,b values are from 0 to 1
	// h = [0,360], s = [0,1], v = [0,1]

	if ( DefaultCompareTrait<double>::IsEQ(dS, 0.0) ) {
		// achromatic (grey)
		dR = dG = dB = dV;
		return ;
	}

	dH = dH < 0.0 ? 0.0 : dH;
	dH /= 60.0; // sector 0 to 5
	int i = (int)FloatTraits<double>::floor(dH);
	if ( i < 0 )
		i = 0;
	double f = dH - i; // factorial part of h
	double p = dV * (1.0 - dS);
	double q = dV * (1.0 - dS * f);
	double t = dV * (1.0 - dS * (1.0 - f));

	switch ( i ) {
	case 0:
		dR = dV;
		dG = t;
		dB = p;
		break;
	case 1:
		dR = q;
		dG = dV;
		dB = p;
		break;
	case 2:
		dR = p;
		dG = dV;
		dB = t;
		break;
	case 3:
		dR = p;
		dG = q;
		dB = dV;
		break;
	case 4:
		dR = t;
		dG = p;
		dB = dV;
		break;
	case 5:
	default:
		dR = dV;
		dG = p;
		dB = q;
		break;
	}
}

////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
#endif
////////////////////////////////////////////////////////////////////////////////
